#include "StatusGrpcClient.h"
#include "../log.h"
#include "../NetGlobal.h"

StatusGrpcClient::StatusGrpcClient()
{
    auto config = ConfigMgr::GetConfig();
    log_info("StatusGrpcClient, host:{}, port:{}, pool_size:{}", 
        config->StatusServerInfo.IP, config->StatusServerInfo.Port, config->StatusServerInfo.PoolSize);

    _pool = std::make_unique<StatusConPool>(config->StatusServerInfo.PoolSize,
                                            config->StatusServerInfo.IP,
                                            std::to_string(config->StatusServerInfo.Port));
}

GetChatServerRsp StatusGrpcClient::GetChatServerInfo(uint32_t uid)
{
    grpc::ClientContext context;
    GetChatServerRsp reply;
    GetChatServerReq request;
    request.set_uid(uid);

    auto stub = _pool->getConnection();
    if (!stub) {
        reply.set_code(ErrorCode::RPCFailure);
        log_error("Failed to get gRPC connection from pool");
        return reply;
    }

    grpc::Status status = stub->GetChatServer(&context, request, &reply);

    // RAII 自动归还
    _pool->returnConnection(std::move(stub));

    if (status.ok()) 
    {
        if(reply.code() != ErrorCode::Success) 
        {
            log_error("RPC call returned error code: {}, msg: {}", reply.code(), reply.msg());
            reply.set_code(reply.code());
            return reply;
        }
        return reply;
    } 
    else 
    {
        reply.set_code(ErrorCode::RPCFailure);
        log_error("RPC call failed: {}", status.error_message());
        return reply;
    }
}

LoginRsp StatusGrpcClient::Login(uint32_t uid, std::string& token)
{
    grpc::ClientContext context;
    LoginReq request;
    request.set_uid(uid);
    request.set_token(token);

    LoginRsp reply;
    auto stub = _pool->getConnection();
    if (!stub) {
        reply.set_code(ErrorCode::RPCFailure);
        log_error("Failed to get gRPC connection from pool");
        return reply;
    }

    grpc::Status status = stub->Login(&context, request, &reply);
    _pool->returnConnection(std::move(stub));

    if (status.ok()) 
    {
        if(reply.code() != ErrorCode::Success) 
        {
            log_error("RPC call returned error code: {}, msg: {}", reply.code(), reply.msg());
            reply.set_code(reply.code());
            return reply;
        }
        return reply;
    }
    else 
    {
        reply.set_code(ErrorCode::RPCFailure);
        log_error("RPC call failed: {}", status.error_message());
        return reply;
    }
}



StatusConPool::StatusConPool(size_t poolSize, std::string host, std::string port)
: _isStop(false), _poolSize(poolSize), _host(std::move(host)), _port(std::move(port))
{
    for (size_t i = 0; i < poolSize; ++i)
    {
        // 创建连接，并将其放入池中
        auto channel = grpc::CreateChannel(_host + ":" + _port, grpc::InsecureChannelCredentials());
        std::unique_ptr<StatusService::Stub> stub(StatusService::NewStub(channel));
        _connections.push(std::move(stub));
    }
}
StatusConPool::~StatusConPool()
{
    Close();
}

std::unique_ptr<StatusService::Stub> StatusConPool::getConnection()
{
    std::unique_lock<std::mutex> lock(_mutex);
    _cond.wait(lock, [this]() { return !_connections.empty() || _isStop.load(); });

    if (_isStop.load())
    {
        return nullptr;
    }

    auto conn = std::move(_connections.front());
    _connections.pop();
    return conn;
}

void StatusConPool::returnConnection(std::unique_ptr<StatusService::Stub> context)
{
    if(!context) { return; }

    std::lock_guard<std::mutex> lock(_mutex);
    if(_isStop.load()) { return; }

    _connections.push(std::move(context));
    _cond.notify_one();
}

void StatusConPool::Close()
{
    {
        std::lock_guard<std::mutex> lock(_mutex);
        _isStop.store(true);
        while (!_connections.empty())
        {
            _connections.pop();
        }
    }
    _cond.notify_all();
}